home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / c / c-bat-0.1n / c-bat-0 / c-bat-0.1 / src / brs_calltree.c next >
Encoding:
C/C++ Source or Header  |  1994-06-16  |  45.1 KB  |  1,390 lines

  1. /*
  2.     brs_calltree: Browsing an Analysis Tool for C-source code;
  3.               Print calltree structure of a project
  4.  
  5.     Copyright (C) 1993  Eckehard Stolz
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation (version 2 of the License).
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21.  
  22.  
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <time.h>
  28.  
  29. #include "hash.h"
  30. #include "c-bat.h"
  31. #include "clients.h"
  32.  
  33.  
  34. /* Types for Hash-Entrys
  35.  */
  36. #define TYPE_FUNCTION      0x1
  37. #define TYPE_FILE          0x2
  38.  
  39. #define MAX_LINE           256  /* maximum of line lenght */
  40.  
  41. /* Flags used in Hash-Table-Entry
  42.  */
  43. #define FLAG_PRINTED      0x1  /* Print Identifier  */
  44. #define FLAG_IGNORE       0x2  /* Ignore Identifier */
  45. #define FLAG_IN_HASH      0x4  /* Allready inserted in Hash-Index-Array  */
  46. #define FLAG_OWN_TREE     0x8  /* use own tree for that function         */
  47. #define FLAG_PROCESSED   0x10  /* Function is allready processed         */
  48. #define FLAG_TERMINATE   0x20  /* Do not process deeper                  */
  49. #define FLAG_CALLED      0x40  /* Used to not process recursive function */
  50. #define FLAG_TREE_CALLED 0x80  /* Used to not process recursive function */
  51. #define FLAG_TREE_TOP   0x100  /* this function is top-node of a tree    */
  52.  
  53. #define max(x,y)   (((x) > (y)) ? (x) : (y))
  54.  
  55.  
  56. /* Additional data, stored in Hash-Table. Here used to store position
  57.    of any function defined in the source-project for the output
  58.    "defined in ... at line ..."
  59.  
  60.  */
  61.  
  62. struct pos_e
  63. { long           file;        /* index of the file in the hash-table        */
  64.   long           line;        /* linenumer, where function has been called  */
  65.   short           len;        /* length of the string "file,line"           */
  66.   struct pos_e  *next;        /* next position                              */
  67.  };
  68.  
  69. struct son_e
  70. { long            son;
  71.   struct pos_e   *pos;
  72.  };
  73.  
  74. struct hash_add_data
  75. { long         level;       /* actual level of call stack (maximum value) */
  76.   long         max_chars;   /* maximum of characters used to print line   */
  77.   long         cnt_sons;    /* cnt of sons of this node                   */
  78.   long         total_cnt_n; /* total cnt of nodes in this leave           */
  79.   long         called;      /* how many times has function been called    */
  80.   long           file;      /* file, where function is defined            */
  81.   long           line;      /* line, where function is defined            */
  82.   struct son_e  *sons;      /* array of sons                              */
  83.   long         father;      /* father of this node                        */
  84.   struct pos_e    pos;      /* position (file/line) where this call is    */
  85.  };
  86.  
  87. typedef struct hash_add_data    t_hash_add;
  88.  
  89.  
  90. /* these strings control the output of the tree.
  91.  */
  92. #define MAX_INDENT  20
  93. #define FILE_LINE_FORMAT  "%s %d"  /* for output of file and line */
  94.  
  95. /*                                 123456789 */
  96. char  blank_pre[MAX_INDENT+1];
  97. char  noblank_pre[MAX_INDENT+1];  
  98. char  last_string[MAX_INDENT+1];
  99. char  mid_string[MAX_INDENT+1];
  100. char  filler_string[MAX_INDENT+1];
  101. char  file_line_format[80] = FILE_LINE_FORMAT;
  102.  
  103. char  c_hline  = '-';
  104. char  c_vline  = '|';
  105. char  c_tline  = '+';
  106. char  c_corner = '`';
  107. char  c_blank  = ' ';
  108. char  c_begin  = ' ';
  109. char  c_filler = '.';
  110.  
  111. short indent_size = 4;
  112.  
  113. #define LEVEL_OFFSET   (strlen(blank_pre))    /* offset for each new level */
  114.  
  115. #define calculate_max_chars(s,l,t) (strlen(s) + (l) * LEVEL_OFFSET + (t))
  116.  
  117. static char funct_filename[MAX_FILENAME];  /* File, where function */
  118.  
  119. static char module_file[MAX_FILENAME];     /* file with module-file-assign*/
  120. static char exclude_file[MAX_FILENAME];    /* list of exclude symbols     */
  121. static char terminate_file[MAX_FILENAME];  /* list of exclude symbols     */
  122.  
  123. static char act_function[MAX_IDENT];           /* act. Function Ident         */
  124.  
  125. static char target_function[2*STRINGSIZE]; /* Ident of searched function  */
  126. static char target_variable[MAX_IDENT];    /* Ident of searched variable  */
  127.  
  128. static char output_line[MAX_LINE];         /* used for creating output */
  129.  
  130. static long   f_line;     /* Source-Line, where function called/defined */
  131. static long   f_line2;    /* Source-Line, where called function defined */
  132.  
  133. static long total_max_chars = 0; /* maximum string for left side of a print-line */
  134. static long total_max_level = 0; /* maximum level in deeperst leave of calltree  */
  135.  
  136. static long line_length  = 80;   /* default for the lenght of a line (may be increased */
  137.                                  /* if necessary )                                     */
  138.  
  139. /* FLAGS
  140.  */
  141.  
  142.  
  143. /* set to 1 if we have to print a full tree: may be BIG !
  144.  */
  145. static short  flag_full_tree = 0;
  146.  
  147. /* set to 1 if we have to print function pointers
  148.  */
  149. static short  flag_funct_pointer = 0;
  150.  
  151. /* set treshhold for starting a new tree for a function depending on the
  152.    numbers of calls to this function
  153.  
  154.    0 ... no own tree for this kind of functions
  155.  */
  156. static short  trshold_called = 0;
  157.  
  158. /* set treshhold for starting a new tree for a function if the
  159.    called-treshhold has been reached, depending on the
  160.    number of nodes of this sub_tree
  161.  
  162.    0 ... cont of sons not important
  163.  */
  164. static short  trshold_sons = 0;
  165.  
  166. /* set to 1 if we should NOT print information to stderr while processing
  167.    functions, symbol-files, ...
  168.  */
  169. static short  quiet_flag = 0;
  170.  
  171. /* set to 1 if we should ignore library symbols !
  172.    library symbols are symbols not defined in the project
  173.  */
  174. static short  ignore_lib_symbols = 0;
  175. static short  mark_lib_symbols = 0;
  176.  
  177. /* Flag, if (and what) position should be printed
  178.  
  179.    0  ... do not print position
  180.    1  ... print position where function called (default)   
  181.    2  ... print position where function defined
  182.  */
  183. static short  flag_print_position = 1;
  184.  
  185.  
  186. /* All symbols, which have to be printed, are stored in the hashtable
  187.    and aditionally stored in this array (by their hash-indizes).
  188.    So we don't have to check the whole hash-table for nonnull-entries
  189.  */
  190. static long *hash_array = NULL;
  191. static long hash_array_cnt = 0;
  192. static long hash_array_size = 0;
  193.  
  194. /* used for locally collecting sons of a function-node
  195.  */
  196. static struct son_e *son_hash_array = NULL;
  197. static long  son_hash_array_cnt = 0;
  198. static long  son_hash_array_size = 0;
  199.  
  200.  
  201. /* prototypes
  202.  */
  203. extern void reset_hashtable(void);
  204. extern long Add_ident_to_hash(char *ident, short flag, void *add_data, short type );
  205. extern long get_total_nodes(long index, long level, struct pos_e *p);
  206. extern void print_all_nodes(long index, long level, struct pos_e *p, char last);
  207. extern void print_line( long level, char *ident, t_hash_add *add, struct pos_e *p, char *suffix, char last_flag);
  208.  
  209.  
  210. /* This function add's a symbol to the symbol-table. If the flag for
  211.    printing is set, the index is added to the hash-index-array which
  212.    causes the symbol to be printed after processing
  213.  
  214.    return-value is the index in the hash-table
  215.  */
  216. long Add_ident_to_hash(char *ident, short flag, void *add_data, short type )
  217. { long index ;
  218.   t_hash_data  h_entry;
  219.  
  220.   if( ident[0] == 0 )
  221.     return; /* nothing to do with an empty item */
  222.  
  223.   strncpy( h_entry.ident, ident, SZE_HASH_IDENT - 1 );
  224.   h_entry.ident[SZE_HASH_IDENT - 1] = 0;
  225.   h_entry.type  = type;
  226.   h_entry.flags = flag;
  227.   h_entry.data  = add_data;
  228.   index = insert_token( &h_entry );
  229.  
  230.   return( index );
  231. }
  232.  
  233.  
  234. /* add index to hash array index to easyly find function-hash-indezes
  235.    again
  236.  */
  237. void Add_to_Hash_Index_Array(long index)
  238. {
  239.  
  240.   hash_array[hash_array_cnt] = index;
  241.   hash_array_cnt++;
  242.  
  243.   if( hash_array_cnt == hash_array_size)
  244.     { hash_array_size += HASH_ARRAY_INIT_SIZE;
  245.       hash_array = realloc( hash_array,
  246.                sizeof( long ) * hash_array_size );
  247.  
  248.       if( !hash_array )
  249.     { fprintf(stderr, "Error ! Cannot allocate %ld Bytes of Memory\n",
  250.            sizeof( long ) * hash_array_size );
  251.       exit(1);
  252.      }
  253.      }
  254.  }
  255.  
  256. /* add index to hash array index to easyly find function-hash-indezes
  257.    again
  258.  */
  259. void Add_to_Son_Array(struct son_e son)
  260. {
  261.  
  262.   son_hash_array[son_hash_array_cnt] = son;
  263.   son_hash_array_cnt++;
  264.  
  265.   if( son_hash_array_cnt == son_hash_array_size)
  266.     { son_hash_array_size += HASH_ARRAY_INIT_SIZE;
  267.       son_hash_array = realloc( son_hash_array,
  268.                sizeof( struct son_e ) * son_hash_array_size );
  269.  
  270.       if( !son_hash_array )
  271.     { fprintf(stderr, "Error ! Cannot allocate %ld Bytes of Memory\n",
  272.            sizeof( struct son_e ) * son_hash_array_size );
  273.       exit(1);
  274.      }
  275.      }
  276.  }
  277.  
  278.  
  279. /* opens a file with symbols and adds them to the symbol-table
  280.  */
  281. void read_symbols(char *file, short flag)
  282. { long         index;
  283.   t_hash_data  data;
  284.   t_hash_add   *p_h_add_s;
  285.   FILE        *fp;
  286.  
  287.  
  288.   fp = fopen( file, "r" );
  289.   if( !fp )
  290.     { fprintf(stderr, "Cannot open File %s !\nAborting !", file );
  291.       exit(1);
  292.      }
  293.  
  294.   while( !feof(fp) )
  295.     { if( fgets( act_function, MAX_IDENT, fp ) )
  296.     { if( act_function[strlen(act_function)-1] == '\n' )
  297.          act_function[strlen(act_function)-1] = 0;
  298.  
  299.           p_h_add_s = malloc( sizeof( t_hash_add ) );
  300.  
  301.           if( !p_h_add_s )
  302.             { fprintf(stderr, "Not enough physical memory available !\n");
  303.               exit(1);
  304.              }
  305.           /* new entry: insert initial values
  306.            */
  307.           p_h_add_s->level       = -1;
  308.           p_h_add_s->called      = 1;
  309.           p_h_add_s->cnt_sons   = 0;
  310.           p_h_add_s->total_cnt_n = 0;
  311.           p_h_add_s->father      = TOKEN_NOT_FOUND;
  312.  
  313.           p_h_add_s->pos.file     = TOKEN_NOT_FOUND;
  314.           p_h_add_s->pos.line     = 0;
  315.           p_h_add_s->pos.next     = NULL;
  316.  
  317.       Add_ident_to_hash( act_function, flag, p_h_add_s, 0 );
  318.          
  319.           if( !quiet_flag )
  320.             fprintf(stderr, "Symbol: \"%s\" \n", act_function);
  321.  
  322.      }
  323.      }
  324.  
  325.   fclose(fp);
  326.  }
  327.  
  328. /* build all strings from the tree-characters.
  329.  
  330.    used to rebuild the strings if they had been changed
  331.  */
  332. void create_output_strings(void)
  333. { short i;
  334.    
  335.   blank_pre[indent_size]    = 0;
  336.   noblank_pre[indent_size]  = 0;
  337.   last_string[indent_size]  = 0;
  338.   mid_string[indent_size]   = 0;
  339.   filler_string[1]          = 0;
  340.  
  341.   for( i = 0; i < indent_size; i++)
  342.    { blank_pre[i] = c_blank;
  343.      noblank_pre[i] = c_blank;
  344.     }
  345.   noblank_pre[0] = c_vline;
  346.   
  347.   for( i = 1; i < indent_size - 1; i++ )
  348.    { last_string[i] = c_hline;
  349.      mid_string[i]  = c_hline;
  350.     }
  351.   mid_string[0]              = c_tline;
  352.   mid_string[indent_size-1]  = c_begin;
  353.   last_string[0]             = c_corner;
  354.   last_string[indent_size-1] = c_begin;
  355.  
  356.   filler_string[0] = c_filler;
  357. }
  358.  
  359.  
  360.  
  361. main( int argc, char *argv[] )
  362. { short  flag;
  363.   short  ret,
  364.          ret2,
  365.          code,
  366.          ignore_this_symbol,
  367.          static_flag;
  368.    
  369.   int    server;
  370.    
  371.   FILE   *fp;
  372.    
  373.   char   funct_in[STRINGSIZE];
  374.   char   funct[STRINGSIZE];
  375.   char   file[2*STRINGSIZE];
  376.   char   file2[2*STRINGSIZE];
  377.   char   module[2*STRINGSIZE];
  378.  
  379.   struct son_e  created_son;
  380.  
  381.   t_hash_add   *p_h_add,
  382.                *p_h_add_s;
  383.  
  384.   t_hash_data  h_data,
  385.                h_data_f,
  386.                h_data_s;
  387.  
  388.   long         i,
  389.                j,
  390.                index,
  391.                line,
  392.                line_end,
  393.                line2,
  394.                index_s;
  395.  
  396.    
  397.    if( argc <= 1 || argv[1][1] == '?' )
  398.      { fprintf(stderr, "Usage: brs_calltree [Options] <funct> [<file>]\n" );
  399.        fprintf(stderr, "Print a calltree from function <funct>, defined in <file>\n");
  400.        fprintf(stderr, "This program needs the browser-server run in background !\n");
  401.        fprintf(stderr, "\nOptions:\n");
  402.        fprintf(stderr, "-b <browser-file>  Connect to server processing this browser file\n");
  403.        fprintf(stderr, "-x <exclude-file>  Exclude symbols given in exclude-file\n");
  404.        fprintf(stderr, "                   format of exclude-file : one symbol per line\n");
  405.        fprintf(stderr, "-s <stop-file>     Stop downwalking at symbols given in stop-file\n");
  406.        fprintf(stderr, "                   format of stop-file : one symbol per line\n");
  407.        fprintf(stderr, "-n <tree-file>     Own tree for every symbol given in tree-file\n");
  408.        fprintf(stderr, "                   format of tree-file : one symbol per line\n");
  409.        fprintf(stderr, "-q                 Quiet: Do not print information to stderr\n");
  410.        fprintf(stderr, "-f                 Include Function-Pointers used outside functions\n");
  411.        fprintf(stderr, "\n");
  412.        fprintf(stderr, "-pc                Print position where functions called (default)\n");
  413.        fprintf(stderr, "-pd                Print position where functions defined\n");
  414.        fprintf(stderr, "-p-                Do not print position at all\n");
  415.        fprintf(stderr, "-lm                Mark library-symbols with \"(L)\"\n");
  416.        fprintf(stderr, "-l-                Do not print library symbols\n");
  417.        fprintf(stderr, "\nOptions controlling look of the output-tree           defaults\n");
  418.        fprintf(stderr, "-i<value>     Numbers of chars for indent (>= 2)    4\n");
  419.        fprintf(stderr, "-F<filename>  File containing formatstring for position \"%%s %%d\"\n");
  420.        fprintf(stderr, "-d<char>      Character for filling line           '.'\n");
  421.        fprintf(stderr, "-ch<char>     Character for horizontal line        '-'\n");
  422.        fprintf(stderr, "-cv<char>     Character for vertical line          '|'\n");
  423.        fprintf(stderr, "-ct<char>     Character for T-line                 '+'\n");
  424.        fprintf(stderr, "-cc<char>     Character for corner                 '`'\n");
  425.        fprintf(stderr, "-cb<char>     Character before function name       ' '\n");
  426.        exit(1);
  427.       }
  428.  
  429.    target_function[0]  = 0;
  430.    funct_filename[0] = 0;
  431.  
  432.    /* we have to preprocess args for looking for the
  433.       -q flag. We need to initialize the hash-table before
  434.       fully parsing arguments
  435.     */   
  436.    for( i = 1; i < argc; i++ )
  437.      { if( argv[i][0] == '-' )
  438.          { switch( argv[i][1] )
  439.              { case 'q' : /* quiet-flag: no Info to stderr */
  440.              quiet_flag = 1;
  441.              break;
  442.  
  443.                default:
  444.                  break;
  445.               }
  446.            }
  447.        }
  448.    
  449.    if( !quiet_flag )
  450.      fprintf( stderr, "Initializing Hashtable ...\n");
  451.  
  452.    init_hashtable ();
  453.  
  454.    for( i = 1; i < argc; i++ )
  455.      { if( argv[i][0] != '-' )
  456.          { /* function or filename */
  457.            if( target_function[0] )
  458.              { if( funct_filename[0] )
  459.                  { fprintf(stderr, "Unknown Option \"%s\" !\n", argv[i] );
  460.                fprintf(stderr, "Type \"brs_calltree -?\" for help !\n" );
  461.                exit(1);
  462.                   }
  463.                else
  464.                   strcpy( funct_filename, argv[i] );
  465.               }
  466.            else
  467.              strcpy( target_function, argv[i] );
  468.           }
  469.        else
  470.        /* ordinary option given: */
  471.          { switch( argv[i][1] )
  472.          { case 'x' : /* Exclude-Filename */
  473.                  if( !quiet_flag )
  474.                    fprintf( stderr, "Reading symbols from exclude-file ...\n");
  475.              if( argv[i][2] )
  476.                { /* Filename given without blank */
  477.                      read_symbols( argv[i] + 2, FLAG_IGNORE );
  478.             }
  479.              else
  480.                { /* Browser-filename is in the next argument
  481.               */
  482.              i++;
  483.                      read_symbols( argv[i], FLAG_IGNORE );
  484.             }
  485.              break;
  486.             
  487.            case 'b' : /* Browser-Filename */
  488.              if( argv[i][2] )
  489.                { /* Filename given without blank */
  490.                      server = brs_get_server_id( argv[i] + 2 );
  491.             }
  492.              else
  493.                { /* Browser-filename is in the next argument
  494.               */
  495.              i++;
  496.                      server = brs_get_server_id( argv[i] );
  497.             }
  498.                  if( server < 0 )
  499.                    { fprintf(stderr, "Server with browser file \"%s\" not found !\n",
  500.                             argv[i] );
  501.                      exit(1);
  502.                     }
  503.                  if( (ret = brs_connect_server( server )) > 0  )
  504.                    { fprintf(stderr, "Server connection failed (Error: %hd) !\n",
  505.                             ret );
  506.                      exit(1);
  507.                     }
  508.              break;
  509.  
  510.            case 's' : /* Stop-Filename */
  511.                  if( !quiet_flag )
  512.                    fprintf( stderr, "Reading symbols from stop-file ...\n");
  513.             
  514.              if( argv[i][2] )
  515.                { /* Filename given without blank */
  516.                      read_symbols( argv[i] + 2, FLAG_TERMINATE );
  517.             }
  518.              else
  519.                { /* Browser-filename is in the next argument
  520.               */
  521.              i++;
  522.              read_symbols( argv[i], FLAG_TERMINATE );
  523.             }
  524.              break;
  525.  
  526.            case 'n' : /* Tree-Filename */
  527.                  if( !quiet_flag )
  528.                    fprintf( stderr, "Reading symbols from tree-file ...\n");
  529.             
  530.              if( argv[i][2] )
  531.                { /* Filename given without blank */
  532.                      read_symbols( argv[i] + 2, FLAG_OWN_TREE );
  533.             }
  534.              else
  535.                { /* Browser-filename is in the next argument
  536.               */
  537.              i++;
  538.              read_symbols( argv[i], FLAG_OWN_TREE );
  539.             }
  540.              break;
  541.  
  542.                case 'p' : /* Print-position */
  543.              switch( argv[i][2] )
  544.                   { case 'c':  /* where function called */
  545.                        flag_print_position = 1;
  546.                        break;
  547.                     case 'd':  /* where function defined */
  548.                        flag_print_position = 2;
  549.                        break;
  550.                     case '-':  /* no position at all */
  551.                        flag_print_position = 0;
  552.                        break;
  553.                     default:  
  554.                    fprintf(stderr, "Unknown Option \"%s\" !\n", argv[i] );
  555.                    fprintf(stderr, "Type \"brs_calltree -?\" for help !\n" );
  556.                    exit(1);
  557.             }
  558.              break;
  559.  
  560.                case 'F' : /* format string for position output */
  561.              if( argv[i][2] )
  562.                { /* Filename given without blank */
  563.                      fp = fopen( argv[i] + 2, "r" );
  564.                      if( !fp )
  565.                    { fprintf(stderr, "Cannot open formatstring-file: \"%s\" !\n", argv[i] + 2 );
  566.                          fprintf(stderr, "Using default !\n");
  567.                          break;
  568.                         }
  569.             }
  570.              else
  571.                { /* Browser-filename is in the next argument
  572.               */
  573.              i++;
  574.                      fp = fopen( argv[i], "r" );
  575.                      if( !fp )
  576.                    { fprintf(stderr, "Cannot open formatstring-file: \"%s\" !\n", argv[i] );
  577.                          fprintf(stderr, "Using default !\n");
  578.                          break;
  579.                         }
  580.             }
  581.                
  582.                  for( j = 0; j < 80; j++)
  583.                    { file_line_format[j] = fgetc(fp);
  584.                      
  585.                      if( file_line_format[j] == EOF || 
  586.                          !isprint(file_line_format[j]) )
  587.                         break;
  588.                     }
  589.                  fclose(fp);
  590.                
  591.                  file_line_format[j] = 0;
  592.              break;
  593.             
  594.                case 'i' : /* number of chars indenting */
  595.                  indent_size = atoi( argv[i] + 2);
  596.                  if( indent_size < 2 || indent_size > 10 )
  597.                { fprintf(stderr, "Illegal value \"%s\" !\n", argv[i] );
  598.                  exit(1);
  599.                     }
  600.                  break;
  601.  
  602.                case 'd' : /* dots */
  603.                  c_filler = (argv[i][2]) ? argv[i][2] : ' ';
  604.                  break;
  605.             
  606.                case 'f' : /* include function-pointers */
  607.                  flag_funct_pointer = 1;
  608.                  break;
  609.  
  610.                case 'l' : /* Library symbols */
  611.                  if( argv[i][2] != '-' && argv[i][2] != 'm' ) 
  612.                { fprintf(stderr, "Cannot recognize library-symbol-option \"%s\" !\n", argv[i] );
  613.                  fprintf(stderr, "Type \"brs_calltree -?\" for help !\n" );
  614.                  exit(1);
  615.                     }
  616.                  ignore_lib_symbols = ( argv[i][2] == '-' ) ? 1 : 0;
  617.                  mark_lib_symbols   = ( argv[i][2] == 'm' ) ? 1 : 0;
  618.  
  619.                  break;
  620.             
  621.                case 'c' : /* Characters */
  622.                  if( argv[i][2] != 'h' && argv[i][2] != 'v' && 
  623.                       argv[i][2] != 't' && argv[i][2] != 'c' &&
  624.                       argv[i][2] != 'b'       )
  625.                { fprintf(stderr, "Cannot recognize char-option \"%s\" !\n", argv[i] );
  626.                  fprintf(stderr, "Type \"brs_calltree -?\" for help !\n" );
  627.                  exit(1);
  628.                     }
  629.                  switch( argv[i][2] )
  630.                    { case 'h': /* horizontal line */
  631.                                c_hline = ( argv[i][3] ) ? argv[i][3] : ' ';
  632.                                break;
  633.                
  634.                      case 'v': /* vertikal line */
  635.                                c_vline = ( argv[i][3] ) ? argv[i][3] : ' ';
  636.                                break;
  637.                
  638.                      case 't': /* T-line */
  639.                                c_tline = ( argv[i][3] ) ? argv[i][3] : ' ';
  640.                                break;
  641.                      case 'c': /* corner */
  642.                                c_corner = ( argv[i][3] ) ? argv[i][3] : ' ';
  643.                                break;
  644.                      case 'b': /* begin */
  645.                                c_begin = ( argv[i][3] ) ? argv[i][3] : ' ';
  646.                                break;
  647.                      default:
  648.                     fprintf(stderr, "Unknown Option \"%s\" !\n", argv[i] );
  649.                     fprintf(stderr, "Type \"brs_calltree -?\" for help !\n" );
  650.                     exit(1);
  651.                    }
  652.                  break;
  653.             
  654.                case 'q' : /* quiet-flag: no Info to stderr */
  655.              quiet_flag = 1;
  656.              break;
  657.  
  658.            default:
  659.              fprintf(stderr, "Unknown Option \"%s\" !\n", argv[i] );
  660.              fprintf(stderr, "Type \"brs_calltree -?\" for help !\n" );
  661.              exit(1);
  662.           }
  663.           }
  664.       }
  665.  
  666.    /* create the strings needed to print the tree
  667.     */
  668.    create_output_strings();
  669.    
  670.    /* initialize hash-index-array used to hold the hash-indizes of the
  671.       processed functions
  672.     */
  673.    hash_array      = malloc(sizeof(long) * HASH_ARRAY_INIT_SIZE);
  674.  
  675.    if( !hash_array )
  676.      { fprintf(stderr, "Error ! Cannot allocate %ld Bytes of Memory\n",
  677.                sizeof( long ) * HASH_ARRAY_INIT_SIZE );
  678.        exit( 1 );
  679.       }
  680.  
  681.    hash_array_size = HASH_ARRAY_INIT_SIZE;
  682.    hash_array_cnt  = 0;
  683.  
  684.    /* initialize index-array for son-entries
  685.     */
  686.    son_hash_array      = malloc(sizeof(struct son_e) * HASH_ARRAY_INIT_SIZE);
  687.  
  688.    if( !son_hash_array )
  689.      { fprintf(stderr, "Error ! Cannot allocate %ld Bytes of Memory\n",
  690.                sizeof( struct son_e ) * HASH_ARRAY_INIT_SIZE );
  691.        exit( 1 );
  692.       }
  693.  
  694.    son_hash_array_size = HASH_ARRAY_INIT_SIZE;
  695.    son_hash_array_cnt  = 0;
  696.  
  697.  
  698.    /* get top-function-info
  699.     */
  700.    ret = brs_get_funct_pos( target_function, funct_filename,
  701.                         file, &line, &line_end, module);
  702.  
  703.    switch( ret )
  704.      { case 0:            break;
  705.        case RET_TIMEOUT:  fprintf(stderr, "No connection !\n");
  706.                           exit(1);
  707.        case RET_ERROR:    fprintf(stderr, "Error pos 0: %s %s \n", file, module);
  708.                           exit(1);
  709.        default:           fprintf(stderr, "Error pos 0: %d (%s %s) \n", ret,
  710.                                            file, module);
  711.                           exit(1);
  712.       }
  713.  
  714.    index = search_token( target_function, &h_data);
  715.  
  716.    if( index != TOKEN_NOT_FOUND &&
  717.        h_data.flags & (FLAG_IGNORE | FLAG_TERMINATE) )
  718.      { fprintf(stderr, "Target-function is exclude or terminate !\n");
  719.        exit(1);
  720.       }
  721.  
  722.    p_h_add = malloc( sizeof( t_hash_add ) );
  723.    if( !p_h_add )
  724.      { fprintf(stderr, "Not enough physical memory available !\n");
  725.        exit(1);
  726.       }
  727.  
  728.    /* init hash-add-struct of top-node
  729.     */
  730.    p_h_add->level       = -1;
  731.    p_h_add->cnt_sons   = 0;
  732.    p_h_add->total_cnt_n = 0;
  733.    p_h_add->called      = 0;
  734.    p_h_add->father      = TOKEN_NOT_FOUND;
  735.  
  736.    p_h_add->file    = search_token( file, NULL);
  737.    if( p_h_add->file == TOKEN_NOT_FOUND )
  738.      { p_h_add->file = Add_ident_to_hash( file, 0,
  739.                                  NULL, TYPE_FILE);
  740.       }
  741.    p_h_add->line    = line;
  742.  
  743.    /* just used to calculate the length of the column "file,line"
  744.     */
  745.    if( flag_print_position == 2 )
  746.      { /* just if definition position has to be printed 
  747.         */
  748.        sprintf( module, file_line_format , file, line );
  749.        p_h_add->pos.len    = strlen(module);
  750.       }
  751.    else
  752.      p_h_add->pos.len    = 0;
  753.  
  754.    p_h_add->max_chars   = calculate_max_chars( target_function, 0, p_h_add->pos.len);
  755.    
  756.    /* Add top-function to hash (every time, even if we do not
  757.       have to print files)
  758.     */
  759.    index = Add_ident_to_hash(target_function, FLAG_IN_HASH |
  760.                                               FLAG_TREE_TOP |
  761.                                               FLAG_OWN_TREE,
  762.                               p_h_add, TYPE_FUNCTION);
  763.  
  764.    Add_to_Hash_Index_Array(index);
  765.    
  766.    if( flag_funct_pointer )
  767.      { p_h_add = malloc( sizeof( t_hash_add ) );
  768.        if( !p_h_add )
  769.          { fprintf(stderr, "Not enough physical memory available !\n");
  770.            exit(1);
  771.           }
  772.  
  773.        /* init hash-add-struct of top-node
  774.         */
  775.        p_h_add->level       = -1;
  776.        p_h_add->cnt_sons   = 0;
  777.        p_h_add->total_cnt_n = 0;
  778.        p_h_add->called      = 0;
  779.        p_h_add->father      = TOKEN_NOT_FOUND;
  780.  
  781.        p_h_add->file        = TOKEN_NOT_FOUND;
  782.        p_h_add->line        = 0;
  783.        p_h_add->pos.len    = 0;
  784.  
  785.        p_h_add->max_chars   = calculate_max_chars( "?", 0, p_h_add->pos.len);
  786.        index = Add_ident_to_hash( "?", FLAG_IN_HASH |
  787.                                        FLAG_OWN_TREE,
  788.                                        p_h_add, TYPE_FUNCTION);
  789.  
  790.        Add_to_Hash_Index_Array(index);
  791.       }
  792.  
  793.    if( !quiet_flag )
  794.      fprintf( stderr, "processing function ...\n");
  795.  
  796.    /* walk through the hash-index-array. initially, there is only the top
  797.       node in it, but it (and therefore hash_array_cnt) will grow as long
  798.       as there are unprocessed functions
  799.     */
  800.    for( i = 0; i < hash_array_cnt; i++ )
  801.      { get_token ( &h_data, hash_array[i] );
  802.  
  803.        ret = 0;
  804.  
  805.        if( h_data.flags & FLAG_IGNORE )
  806.          continue;
  807.  
  808.        if( h_data.flags & FLAG_TERMINATE )
  809.          ret = RET_END;
  810.  
  811.        if( !quiet_flag )
  812.          fprintf( stderr, "%ld/%ld: %s ", i, hash_array_cnt, h_data.ident );
  813.    
  814.        p_h_add = NULL;
  815.        if( h_data.data )
  816.           p_h_add = (t_hash_add *)h_data.data;
  817.  
  818.        /* copy the name of the function
  819.         */
  820.        if( strcmp( h_data.ident, "?" ) )
  821.           strcpy( funct_in, h_data.ident );
  822.        else
  823.           strcpy( funct_in, "" );
  824.       
  825.        /* get filename of this function */
  826.        if( p_h_add->file != TOKEN_NOT_FOUND )
  827.           get_token ( &h_data_f, p_h_add->file ); 
  828.        else
  829.           strcpy( h_data_f.ident, "" );
  830.  
  831.        /* init local hash-indx-array to hold all the sons of this
  832.           node
  833.         */
  834.        son_hash_array_cnt = 0;
  835.  
  836.        /* get all called function of this function
  837.         */
  838.        while( !ret )
  839.         { ret = brs_get_funct_calls( funct_in, h_data_f.ident,
  840.                           !flag_full_tree,
  841.                           funct, file, &line, module, &static_flag);
  842.  
  843.           ignore_this_symbol = 0; /* default: add this symbol to son-array */
  844.          
  845.           if( !ret )
  846.             { /* we found a son-node */
  847.               /* check if function allready in hash-table
  848.                */
  849.               if( !quiet_flag )
  850.                 fprintf( stderr, "." );
  851.             
  852.               index_s = search_token(funct, &h_data_s);
  853.               if( index_s == TOKEN_NOT_FOUND )
  854.                 { /* new function: allocate memory for additional data
  855.                    */
  856.                   p_h_add_s = malloc( sizeof( t_hash_add ) );
  857.                   if( !p_h_add_s )
  858.                     { fprintf(stderr, "Not enough physical memory available !\n");
  859.                       exit(1);
  860.                      }
  861.                   /* new entry: insert initial values
  862.                    */
  863.                   p_h_add_s->level       = -1;
  864.                   p_h_add_s->called      = 1;
  865.                   p_h_add_s->cnt_sons   = 0;
  866.                   p_h_add_s->total_cnt_n = 0;
  867.                   p_h_add_s->father      = TOKEN_NOT_FOUND;
  868.                
  869.                   /* we have to get the definition-position of the function by using
  870.                      the get_funct_pos-call. the above function returns just the call-
  871.                      position.
  872.                      first try static function in file where this function was called
  873.                    */ 
  874.                   if( static_flag )
  875.                      ret2 = brs_get_funct_pos( funct, file, file2, &line2, 
  876.                                            &line_end, module);
  877.                   else
  878.                      ret2 = brs_get_funct_pos( funct, "", file2, &line2, 
  879.                                            &line_end, module);
  880.             
  881.                   switch( ret2 )
  882.                    { case 0: case RET_END: /* store definition position */
  883.                            p_h_add_s->file = search_token( file2, NULL);
  884.                            if( p_h_add_s->file == TOKEN_NOT_FOUND )
  885.                              { p_h_add_s->file =
  886.                                       Add_ident_to_hash( file2, 0,
  887.                                                          NULL, TYPE_FILE);
  888.                               }
  889.                            p_h_add_s->line = line2;
  890.                            break;
  891.                
  892.                      case RET_TIMEOUT:  fprintf(stderr, "No connection !\n");
  893.                                         exit(1);
  894.                      case RET_ERROR:    /* symbol could not be found withing the project
  895.                                          */
  896.                            p_h_add_s->file = TOKEN_NOT_FOUND;
  897.                            p_h_add_s->line = 0;
  898.                            line2 = 0;
  899.                            file2[0] = 0;
  900.                   
  901.                            /* library symbol: do not add to son array */
  902.                            if( ignore_lib_symbols )
  903.                              ignore_this_symbol = 1;
  904.                   
  905.                           break;
  906.                      default:           fprintf(stderr, "Error Pos2: %d (%s %s) \n", ret,
  907.                                                          file2, module);
  908.                                         exit(1);
  909.                     }
  910.                 
  911.  
  912.                   p_h_add_s->pos.file     =
  913.                           search_token( file, NULL);
  914.                   if( p_h_add_s->pos.file == TOKEN_NOT_FOUND )
  915.                     { p_h_add_s->pos.file =
  916.                              Add_ident_to_hash(file, 0, NULL, TYPE_FILE);
  917.                      }
  918.                   p_h_add_s->pos.line    = line;
  919.                   p_h_add_s->pos.next    = NULL;
  920.                
  921.                   /* just used to calculate the length of the column "file,line"
  922.                    */
  923.                   if( flag_print_position == 2 )
  924.                     { /* definition position */
  925.                       sprintf( module, file_line_format, file2, line2 );
  926.                       p_h_add_s->pos.len    = strlen(module);
  927.                      }
  928.                   else if ( flag_print_position == 1 )
  929.                     { /* call position */
  930.                       sprintf( module, file_line_format, file, line );
  931.                       p_h_add_s->pos.len    = strlen(module);
  932.                      }
  933.                   else
  934.                     p_h_add_s->pos.len     = 0;
  935.  
  936.                   index_s = Add_ident_to_hash(funct, FLAG_IN_HASH,
  937.                               p_h_add_s, TYPE_FUNCTION);
  938.  
  939.                   Add_to_Hash_Index_Array(index_s);
  940.  
  941.                   created_son.pos = &(p_h_add_s->pos);
  942.                   created_son.son = index_s;
  943.  
  944.                  }
  945.                else /* take pointer of allready allocated memory */
  946.                  { struct pos_e *tmp_pos, *last_pos;
  947.  
  948.                    /* if we have to ignore this symbol: continue with
  949.                       next son
  950.                     */
  951.                    if( h_data_s.flags & FLAG_IGNORE )
  952.                      continue;
  953.  
  954.  
  955.                    if( !(h_data_s.flags & FLAG_IN_HASH) )
  956.                      { /* This ident is not stored in hash-array index.
  957.                           it has probaly entered by terminate or other
  958.                           files
  959.                         */
  960.  
  961.                        Add_to_Hash_Index_Array(index_s);
  962.  
  963.                        set_token_flag( index_s, h_data_s.flags | FLAG_IN_HASH );
  964.                       }
  965.  
  966.                    p_h_add_s = (t_hash_add *)h_data_s.data;
  967.                 
  968.                    /* library symbole - maybe we have to ignore it */
  969.                    if( p_h_add_s->file == TOKEN_NOT_FOUND && ignore_lib_symbols )
  970.                      ignore_this_symbol = 1;
  971.                
  972.                    else /* symbol has to be entered */
  973.                      { /* update entry:
  974.                         */
  975.                        p_h_add_s->called += 1;
  976.  
  977.                        /* add new position to position list
  978.                         */
  979.                        last_pos = &(p_h_add_s->pos);
  980.                        tmp_pos = p_h_add_s->pos.next;
  981.  
  982.                        while( tmp_pos )  /* get to end of the list */
  983.                          { last_pos = tmp_pos;
  984.                            tmp_pos  = tmp_pos->next;
  985.                           }
  986.  
  987.                        /* create a new position entry and add this one to the
  988.                           position-list of this call
  989.                         */
  990.                        tmp_pos = (struct pos_e *)malloc( sizeof(struct pos_e) );
  991.  
  992.                        tmp_pos->file     =
  993.                               search_token( file, NULL);
  994.                        if( tmp_pos->file == TOKEN_NOT_FOUND )
  995.                          { tmp_pos->file =
  996.                                   Add_ident_to_hash( file, 0,
  997.                                                     NULL, TYPE_FILE);
  998.                           }
  999.                        tmp_pos->line    = line;
  1000.                        tmp_pos->next    = NULL;
  1001.                
  1002.                        /* just used to calculate the length of the column "file,line"
  1003.                         */
  1004.                        if( flag_print_position == 2 )
  1005.                          { /* definition position -> allready calculated
  1006.                             */
  1007.                            /* sprintf( module, file_line_format, 
  1008.                                     get_symbol( p_h_add_s->file ), p_h_add_s->line );
  1009.                             */
  1010.                            tmp_pos->len    = last_pos->len;
  1011.                           }
  1012.                        else if ( flag_print_position == 1 )
  1013.                          { /* call position */
  1014.                            sprintf( module, file_line_format, file, line );
  1015.                            tmp_pos->len    = strlen(module);
  1016.                           }
  1017.                        else
  1018.                          tmp_pos->len     = 0;
  1019.  
  1020.                        last_pos->next = tmp_pos;
  1021.  
  1022.                        created_son.pos = tmp_pos;
  1023.                        created_son.son = index_s;
  1024.                       }
  1025.                   }
  1026.  
  1027.                /* Store this son in the son_hash_array
  1028.                 */
  1029.                if( !ignore_this_symbol )
  1030.                   Add_to_Son_Array( created_son );
  1031.             
  1032.              } /* endif !ret */
  1033.            else
  1034.             { switch( ret )
  1035.                { case 0: case RET_END:
  1036.                                     break;
  1037.                
  1038.                  case RET_TIMEOUT:  fprintf(stderr, "No connection !\n");
  1039.                                     exit(1);
  1040.                
  1041.                  case RET_ERROR:    /* This function is not defined in the project:
  1042.                                        continue as it has no sons !
  1043.                                      */
  1044.                                     break;
  1045.                
  1046.                  default:           fprintf(stderr, "Error Pos 1: %d (%s %s) \n", ret,
  1047.                                                      funct, file);
  1048.                                     exit(1);
  1049.                 }
  1050.              }
  1051.  
  1052.          } /* endwhile */
  1053.    
  1054.        if( !quiet_flag )
  1055.          fprintf( stderr, "\n" );
  1056.             
  1057.  
  1058.  
  1059.        p_h_add->cnt_sons = son_hash_array_cnt;
  1060.  
  1061.        p_h_add->sons = (struct son_e *)malloc( sizeof(struct son_e) * son_hash_array_cnt);
  1062.        if( !(p_h_add->sons) )
  1063.          { fprintf(stderr, "Not enough physical memory available !\n");
  1064.            exit(1);
  1065.           }
  1066.  
  1067.        /* copy the indizes of the sons of this node to the father-node
  1068.         */
  1069.        memcpy( p_h_add->sons, son_hash_array,
  1070.                  sizeof(struct son_e) * son_hash_array_cnt);
  1071.       } /* next i */
  1072.  
  1073.  
  1074.   if( !quiet_flag )
  1075.     fprintf( stderr, "calculating nodes for each subtree ...\n" );
  1076.    
  1077.   for( i = 0; i < hash_array_cnt; i++ )
  1078.     { get_token ( &h_data, hash_array[i] );
  1079.  
  1080.        if( h_data.flags & FLAG_IGNORE )
  1081.          continue;
  1082.  
  1083.        if( h_data.flags & FLAG_OWN_TREE )
  1084.          { /* for every own tree calculate numbers of nodes !
  1085.               maybe new trees has to be created
  1086.             */
  1087.            if( h_data.data )
  1088.               p_h_add = (t_hash_add *)h_data.data;
  1089.          
  1090.            get_total_nodes( hash_array[i], 0, &(p_h_add->pos) );
  1091.            if( !quiet_flag )
  1092.              fprintf( stderr, "subtree: %s\n", h_data.ident );
  1093.           }
  1094.       }
  1095.    
  1096.   if( !quiet_flag )
  1097.     fprintf( stderr, "Print subtrees ...\n" );
  1098.    
  1099.   for( i = 0; i < hash_array_cnt; i++ )
  1100.     { get_token ( &h_data, hash_array[i] );
  1101.  
  1102.        if( h_data.flags & FLAG_IGNORE )
  1103.          continue;
  1104.  
  1105.        if( h_data.flags & FLAG_OWN_TREE )
  1106.          { /* for every own tree calculate numbers of nodes !
  1107.               maybe new trees has to be created
  1108.             */
  1109.            if( h_data.data )
  1110.               p_h_add = (t_hash_add *)h_data.data;
  1111.          
  1112.            printf("\n\n\n");
  1113.          
  1114.            print_all_nodes( hash_array[i], 0, &(p_h_add->pos), 1);
  1115.           }
  1116.       }
  1117.    
  1118.    brs_disconnect_server();
  1119.  
  1120.  } /* end main */
  1121.  
  1122.  
  1123.  
  1124. /* This function is recursivly called to process a calltree and returns
  1125.    the number of nodes in a subtree
  1126.  */
  1127. static t_hash_data  H_data;
  1128. static short        j;
  1129.  
  1130. long get_total_nodes(long index, long level, struct pos_e *pos)
  1131. { t_hash_add  *p_h_add;
  1132.   long         i;
  1133. #ifdef CALLTREE_DEBUG
  1134.   char        *ident;
  1135. #endif
  1136.  
  1137.   get_token( &H_data, index);
  1138.   p_h_add = (t_hash_add *)H_data.data;
  1139.    
  1140. #ifdef CALLTREE_DEBUG
  1141.   ident = H_data.ident;
  1142.   for( j = 0; j < level; j++ )
  1143.     fprintf(stderr, "  " );
  1144.    
  1145.   fprintf(stderr, "%s (%d)", H_data.ident, level );
  1146.   fflush( stderr );
  1147. #endif
  1148.  
  1149.   /* calculate the numer of characters used to print this function in this
  1150.      tree. Used to know the offset for the filenames in the output
  1151.    */
  1152.   p_h_add->max_chars = max( calculate_max_chars( H_data.ident, level, pos->len),
  1153.                             p_h_add->max_chars);
  1154.    
  1155.   total_max_level    = max( level, total_max_level );
  1156.  
  1157.   total_max_chars = max( total_max_chars, p_h_add->max_chars);
  1158.  
  1159.   if( p_h_add->level != -1 )
  1160.     { /* recursion: this node is allready called in this leave
  1161.        */
  1162. #ifdef CALLTREE_DEBUG
  1163.       /* fprintf(stderr, " R\n" ); */
  1164. #endif
  1165.       return( 1 );
  1166.      }
  1167.  
  1168.   if( p_h_add->cnt_sons == 0 )
  1169.     { /* terminal node - no sons */
  1170.       p_h_add->total_cnt_n = 0;
  1171.       p_h_add->level       = -1;
  1172.  
  1173. #ifdef CALLTREE_DEBUG
  1174.       fprintf(stderr, " T\n" );
  1175.       fflush( stderr );
  1176. #endif
  1177.       return( 1 );
  1178.      }
  1179.  
  1180.   if( level && (H_data.flags & FLAG_OWN_TREE) )
  1181.     { /* this node will get an own tree: return if not top-node  */
  1182.       p_h_add->total_cnt_n = 0;
  1183.       p_h_add->level       = -1;
  1184. #ifdef CALLTREE_DEBUG
  1185.       fprintf(stderr, " O\n" );
  1186.       fflush( stderr );
  1187. #endif
  1188.       return( 1 );
  1189.      }
  1190.  
  1191.   p_h_add->level = level;
  1192.   p_h_add->total_cnt_n = 0;
  1193.  
  1194. #ifdef CALLTREE_DEBUG
  1195.   fprintf(stderr, "\n" );
  1196.   fflush( stderr );
  1197. #endif
  1198.  
  1199.   for( i = 0; i < p_h_add->cnt_sons; i++ )
  1200.     { 
  1201. #ifdef CALLTREE_DEBUG
  1202.       fprintf(stderr, "%s [%ld:%ld/%ld] ", ident, level, i,
  1203.                  p_h_add->cnt_sons  );
  1204.       fflush( stderr );
  1205. #endif
  1206.  
  1207.       p_h_add->total_cnt_n +=
  1208.          get_total_nodes( p_h_add->sons[i].son, level + 1, 
  1209.                           p_h_add->sons[i].pos );
  1210.      }
  1211. #ifdef CALLTREE_DEBUG
  1212.   fprintf(stderr, "\n" );
  1213.   fflush( stderr );
  1214. #endif
  1215.  
  1216.   /* reset this node */
  1217.   p_h_add->level = -1;
  1218.  
  1219.   /* find out, if we have to use an own tree for this node
  1220.    */
  1221.   if( trshold_called )
  1222.    { if( p_h_add->called >= trshold_called &&
  1223.          p_h_add->total_cnt_n >= trshold_sons )
  1224.        { /* this function should be printed in an own tree
  1225.           */
  1226.          set_token_flag( index, get_token_flag(index) | FLAG_OWN_TREE );
  1227.         }
  1228.     }
  1229.  
  1230.   return( p_h_add->total_cnt_n );
  1231.  }
  1232.  
  1233.  
  1234. /* This function is recursivly called to process a calltree and prints
  1235.    a line for every called function
  1236.  */
  1237. void print_all_nodes(long index, long level, struct pos_e *pos, char last)
  1238. { t_hash_add  *p_h_add;
  1239.   long         i;
  1240.  
  1241.   get_token( &H_data, index);
  1242.   p_h_add = (t_hash_add *)H_data.data;
  1243.  
  1244.  
  1245.   if( p_h_add->level != -1 )
  1246.     { /* recursion: this node is allready called in this leave
  1247.        */
  1248.       print_line( level, H_data.ident, p_h_add, pos, "... (R) ", last);
  1249.       return;
  1250.      }
  1251.  
  1252.   if( level && (H_data.flags & FLAG_OWN_TREE) )
  1253.     { /* This node will (or has been allready) printed in an own tree !
  1254.          Do not process further
  1255.        */
  1256.       p_h_add->level = -1;
  1257.  
  1258.       print_line( level, H_data.ident, p_h_add, pos, "... (T) ", last);
  1259.       return;
  1260.      }
  1261.  
  1262.   if( p_h_add->cnt_sons == 0 )
  1263.     { /* terminal node - no sons - might also be a library symbol */
  1264.       p_h_add->level = -1;
  1265.  
  1266.       if( p_h_add->file != TOKEN_NOT_FOUND || !mark_lib_symbols )
  1267.         print_line( level, H_data.ident, p_h_add, pos, " ", last);
  1268.       else
  1269.         print_line( level, H_data.ident, p_h_add, pos, " (L) ", last);
  1270.       return;
  1271.      }
  1272.  
  1273.   p_h_add->level = level;
  1274.  
  1275.   print_line( level, H_data.ident, p_h_add, pos, " ", last); 
  1276.    
  1277.   for( i = 0; i < p_h_add->cnt_sons; i++ )
  1278.     { print_all_nodes( p_h_add->sons[i].son, level + 1,
  1279.                        p_h_add->sons[i].pos,
  1280.                        (i == (p_h_add->cnt_sons)-1) ? 1 : 0 );
  1281.      }
  1282.  
  1283.   /* reset this node */
  1284.   p_h_add->level = -1;
  1285.  
  1286.   return;
  1287.  }
  1288.  
  1289.  
  1290.  
  1291. void print_line( long level, char *ident, t_hash_add  *add, struct pos_e *pos, 
  1292.                  char *suffix, char last_flag)
  1293. { static char *last_level_flags = NULL;
  1294.   long         i;
  1295.  
  1296.   output_line[0] = 0;
  1297.         
  1298.   if( !last_level_flags )
  1299.      { last_level_flags = malloc( total_max_level + 2 );
  1300.        if( !last_level_flags )
  1301.           { fprintf(stderr, "Not enough physical memory available !\n");
  1302.             exit(1);
  1303.            }
  1304.       }
  1305.    
  1306.   last_level_flags[level] = last_flag;
  1307.  
  1308.   /* Do the indenting 
  1309.    */    
  1310.   for( i = 1; i < level; i++ )
  1311.     { if( last_level_flags[i] )
  1312.         { /* last flag set in this level: print an empty column
  1313.            */
  1314.           sprintf( output_line + strlen(output_line), "%s" , blank_pre );
  1315.          }
  1316.       else
  1317.         { /* last flag not set in this level: print like "|  "
  1318.            */
  1319.           sprintf( output_line + strlen(output_line), "%s" , noblank_pre );
  1320.          }
  1321.      }
  1322.   
  1323.   if( level ) /* only indenting, if we are not at toplevel */
  1324.    { if( last_flag )
  1325.        sprintf( output_line + strlen(output_line), "%s", last_string );
  1326.      else
  1327.        sprintf( output_line + strlen(output_line),"%s", mid_string );
  1328.     }
  1329.   
  1330.   /* Output the symbol
  1331.    */
  1332.   if( strlen(output_line) + strlen(ident) + strlen( suffix) > line_length )
  1333.     { /* does not fit in this line ! create a new one and indent data
  1334.        */
  1335.       printf( "%s\n", output_line );
  1336.       output_line[0] = 0;
  1337.       for( i = line_length; i > strlen(ident) + strlen( suffix) + pos->len + 8; i--)
  1338.         { sprintf( output_line + strlen(output_line)," " );
  1339.          }
  1340.      }
  1341.   sprintf( output_line + strlen(output_line), "%s%s", ident, suffix );
  1342.  
  1343.   /* print no position or print called-position and main function:
  1344.     
  1345.      do nothing and return
  1346.    */
  1347.   if( !flag_print_position || (flag_print_position == 1 && level == 0) )
  1348.     { printf( "%s\n", output_line );
  1349.       return;
  1350.      }
  1351.    
  1352.   if( flag_print_position == 2 && add->file == TOKEN_NOT_FOUND )
  1353.     { /* definition position of function unknown
  1354.        */
  1355.       printf( "%s\n", output_line );
  1356.       return;
  1357.      }
  1358.  
  1359.   if( strlen(output_line) + pos->len > line_length )
  1360.     { /* file/line does not fit in this line ! create a new one and indent data
  1361.        */
  1362.       printf( "%s\n", output_line );
  1363.       output_line[0] = 0;
  1364.       for( i = line_length; i > pos->len + 8; i--)
  1365.         { sprintf( output_line + strlen(output_line)," " );
  1366.          }
  1367.      }
  1368.    
  1369.   /* print dots */
  1370.   for( i = strlen(output_line); i < line_length - pos->len; i++ )
  1371.     { sprintf( output_line + strlen(output_line), "%s", filler_string);
  1372.      }
  1373.    
  1374.   
  1375.   if( flag_print_position == 1 )
  1376.     { /* Print called position provided by the pos-arg
  1377.        */
  1378.       sprintf( output_line + strlen(output_line), file_line_format, 
  1379.                    get_symbol(pos->file), pos->line);
  1380.      }
  1381.   else if( flag_print_position == 2 )
  1382.     { /* Print definition position in add
  1383.        */
  1384.       sprintf( output_line + strlen(output_line), file_line_format, 
  1385.                    get_symbol(add->file), add->line);
  1386.      }
  1387.    
  1388.   printf( "%s\n", output_line );
  1389. }
  1390.